﻿// -----------------------------------------------------------------------
// <copyright file="Settings.cs" company="Abyssalsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Metal.Config
{
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Xml;

    /// <summary>
    /// Provides methods like load / save application settings.
    /// </summary>
    public class Settings
    {
        /// <summary>Stores a reference to this instance</summary>
        private static Settings instance = null;

        /// <summary>Used to load xml from file</summary>
        private XmlDocument xmlDocument = new XmlDocument();

        /// <summary>Stores the path to settings file</summary>
        private string documentPath;

        /// <summary> Prevents a default instance of the Settings class from being created. </summary>
        private Settings()
        {
            this.LoadSettings();
        }

        /// <summary> Gets the current instance of this class (Singleton - Thread safety) </summary>
        public static Settings Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Settings();
                }

                return instance;
            }
        }

        /// <summary>
        /// Load settings from xml file
        /// </summary>
        public void LoadSettings()
        {
            try
            {
                this.documentPath = Paths.UserFolder + "settings.xml";
                this.xmlDocument.Load(this.documentPath);

                // Load language file
                Resources.MessageProvider.LoadLanguageFile(this.GetValue("LastSettings.Language", "English"));
            }
            catch
            {
                this.xmlDocument.LoadXml("<settings></settings>");
            }
        }

        /// <summary>Get setting if is integer</summary>
        /// <param name="xPath">xpath to get value</param>
        /// <param name="defaultValue">Returning value if not found</param>
        /// <returns>Returns setting from the xml file</returns>
        public int GetValue(string xPath, int defaultValue)
        {
            xPath = xPath.Replace(".", "/");
            return Convert.ToInt32(this.GetValue(xPath, Convert.ToString(defaultValue)));
        }

        /// <summary>Get setting if is boolean</summary>
        /// <param name="xPath">xpath to get value</param>
        /// <param name="defaultValue">Returning value if not found</param>
        /// <returns>Returns setting from the xml file</returns>
        public bool GetValue(string xPath, bool defaultValue)
        {
            xPath = xPath.Replace(".", "/");
            return Convert.ToBoolean(this.GetValue(xPath, Convert.ToString(defaultValue)));
        }

        /// <summary>Get setting if is string</summary>
        /// <param name="xPath">xpath to get value</param>
        /// <param name="defaultValue">Returning value if not found</param>
        /// <returns>Returns setting from the xml file</returns>
        public string GetValue(string xPath, string defaultValue)
        {
            xPath = xPath.Replace(".", "/");
            XmlNode xmlNode = this.xmlDocument.SelectSingleNode("settings/" + xPath);
            if (xmlNode != null)
            {
                return xmlNode.InnerText;
            }
            else
            {
                return defaultValue;
            }
        }

        /// <summary>Set setting if is integer</summary>
        /// <param name="xPath">xpath to get value</param>
        /// <param name="value">The value to save</param>
        public void SetValue(string xPath, int value)
        {
            xPath = xPath.Replace(".", "/");
            this.SetValue(xPath, Convert.ToString(value));
        }

        /// <summary>Set setting if is boolean</summary>
        /// <param name="xPath">xpath to get value</param>
        /// <param name="value">The value to set</param>
        public void SetValue(string xPath, bool value)
        {
            xPath = xPath.Replace(".", "/");
            this.SetValue(xPath, Convert.ToString(value));
        }

        /// <summary>Set setting if is string</summary>
        /// <param name="xPath">xpath to get value</param>
        /// <param name="value">The value to set</param>
        public void SetValue(string xPath, string value)
        {
            xPath = xPath.Replace(".", "/");
            XmlNode xmlNode = this.xmlDocument.SelectSingleNode("settings/" + xPath);
            if (xmlNode == null)
            {
                xmlNode = this.CreateMissingNode("settings/" + xPath);
            }

            xmlNode.InnerText = value;

            // TODO: This probably should be put in a separate method, and should not be called for each value change?
            this.xmlDocument.Save(this.documentPath);
        }

        /// <summary>Create the node if is missing</summary>
        /// <param name="xPath">xpath to missing value</param>
        /// <returns>Returns the node</returns>
        private XmlNode CreateMissingNode(string xPath)
        {
            string[] xPathSections = xPath.Split('/');
            string currentXPath = string.Empty;
            XmlNode testNode = null;
            XmlNode currentNode = this.xmlDocument.SelectSingleNode("settings");
            foreach (string xPathSection in xPathSections)
            {
                currentXPath += xPathSection;
                testNode = this.xmlDocument.SelectSingleNode(currentXPath);
                if (testNode == null)
                {
                    currentNode.InnerXml += "<" +
                                xPathSection + "></" +
                                xPathSection + ">";
                }

                currentNode = this.xmlDocument.SelectSingleNode(currentXPath);
                currentXPath += "/";
            }

            return currentNode;
        }
    }
}
